#include <fixedqueue.h>
#include <i386.h>
#include <debug.h>

/* 
 * q->write es a donde voy a grabar el prox byte
 * q->read es a donde voy a leer el prox byte
 */
#define DEBUG_MM_FQ(x)
//#define DEBUG_MM_FQ(x) x

void
fixedqueue_init( fqueue * q, int max, char * buffer )
{
	q->max = max;
	q->read = 0;
	q->write = 0;
	q->status = 0;
	q->sem_pop = SEM_NEW(0);
	q->sem_push = SEM_NEW(0);
	q->pop_size = 0;
	q->push_size = 0;
	q->data = buffer;
}

int
fixedqueue_push( fqueue * q, char c )
{
	DEBUG_MM_FQ(debug_log("FQ PUSH %x \n", (uint_32) c));
	
	if (q->status && q->read == q->write)
	{
		DEBUG_MM_FQ(debug_log("- NO SPACE \n"));
		return -1;
	}
	q->data[q->write] = c;
	q->write = (q->write + 1) % q->max;
	q->status = 1;

	if ( q->pop_size != 0 && q->pop_size <= fixedqueue_size(q) )
		sem_signaln(&(q->sem_pop));
		
	return 0;
}

int
fixedqueue_pop( fqueue * q, char * c )
{
	DEBUG_MM_FQ(debug_log("FQ POP \n"));
	if (q->read == q->write && !q->status)
	{
		DEBUG_MM_FQ(debug_log("- NO DATA \n"));
		return -1;
	}
	*c = q->data[q->read];
	q->read = (q->read + 1) % q->max;
	if (q->read == q->write)
		q->status = 0;
	sem_signaln(&(q->sem_push));
	return 0;
}

int
fixedqueue_waitpush( fqueue * q, int s, const char * c )
{
	// REVISAR
	int ss = s;
	while (s > 0)
	{
		if( fixedqueue_push( q, c[0] ) )
		{
			DEBUG_MM_FQ(debug_log("FQ PUSH LOCKED\n", (uint_32) c));
			sem_wait(&(q->sem_push));
		}
		else
		{
			c ++;
			s --;
		}
	}
	return ss-s;
}

int
fixedqueue_waitpop( fqueue * q, int s, char * c )
{
	if ( s > fixedqueue_size(q))
	{
		DEBUG_MM_FQ(debug_log("FQ POP LOCKED\n", (uint_32) c));
		q->pop_size = s;
		sem_wait(&(q->sem_pop));
		//breakpoint();
		q->pop_size = 0;
	}
	return fixedqueue_nowaitpop(q, s, c);
}

int
fixedqueue_nowaitpush( fqueue * q, int s, char * c )
{
	int ss = s;
	while (s > 0 && fixedqueue_push( q, c[0] ) == 0)
	{
		c ++;
		s --;
	}
	return ss-s;
}

int
fixedqueue_nowaitpop( fqueue * q, int s, char * c )
{
	int ss = s;
	while (s > 0 && fixedqueue_pop( q, c ) == 0)
	{
		c ++;
		s --;
	}
	return ss-s;
}

int
fixedqueue_size( fqueue * q )
{
	if ( q->read < q->write )
		return q->write - q->read;
	if ( q->write < q->read )
		return q->max - q->read + q->write;
		
	//if ( q->read == q->write )
		return 0;
}
